const models = require("../db/mysqldb/index");
const {
  encrypt,
  validate,
  getClientIp,
  success,
  fail,
  CODE,
} = require("../utils/utils");
const { saltTime, expireTime, secretOrkey } = require("../config/index");
const jwt = require("jsonwebtoken");
const { DataSystemUserModel } = require("../models/sys_user");
const { DataSystemLogininforModel } = require("../models/sys_logininfor");
const { DataSystemUserPostModel } = require("../models/sys_user_post");
const { DataSystemUserRoleModel } = require("../models/sys_user_role");
const { DataSystemDeptModel } = require("../models/sys_dept");
const { DataSystemRoleMenuModel } = require("../models/sys_role_menu");
const { DataSystemMenuModel } = require("../models/sys_menu");
const { getDataFromCache, deleteDataToCache } = require("../utils/nodeCache");
const { getUserDataFromRedis } = require("../utils/userRedis");

const logger = require("../utils/logger");
const config = require("../config/index");
const {
  setUserDataToRedis,
  deleteUserDataToRedis,
} = require("../utils/userRedis");
const { getAddr } = require("../utils/getAddr");

class SysUserController {
  /**
   * @description 登陆
   * @param {*} user_number
   * @param {*} password
   * @param {*} captcha
   */
  static async login (ctx, next) {
    const { user_number, password, captcha } = ctx.request.body;
    try {
      const ip = getClientIp(ctx.req);
      const login_location = await getAddr(ip);
      const { os, platform, browser } = ctx.userAgent;
      if (!captcha) {
        await DataSystemLogininforModel.create({
          login_name: user_number,
          os,
          platform,
          browser,
          login_location,
          ipaddr: ip,
          status: "0",
          msg: "请输入验证码",
        });
        return (ctx.body = fail([], `请输入验证码`, CODE.BUSINESS_ERROR));
      }
      if (!user_number || !password) {
        await DataSystemLogininforModel.create({
          login_name: user_number,
          os,
          platform,
          browser,
          login_location,
          ipaddr: ip,
          status: "0",
          msg: "请输入用户名或密码",
        });
        return (ctx.body = fail([], `请输入用户名或密码`, CODE.BUSINESS_ERROR));
      }
      let captchaIp = "captcha-" + getClientIp(ctx.req);
      // const cacheCaptha =  await getDataFromCache(captchaIp);
      // if (cacheCaptha !== captcha) {
      //   ctx.body = fail([], `验证码错误`, CODE.BUSINESS_ERROR);
      //   return;
      // }
      deleteDataToCache(captchaIp);
      const user = await DataSystemUserModel.findBySystemUserNumber({
        user_number,
      });
      if (!user) {
        await DataSystemLogininforModel.create({
          login_name: user_number,
          os,
          platform,
          browser,
          login_location,
          ipaddr: ip,
          status: "0",
          msg: "用户不存在",
        });
        return (ctx.body = fail([], `用户不存在!`, CODE.BUSINESS_ERROR));
      }
      const opassword = await validate(password, user.password);
      if (!opassword) {
        await DataSystemLogininforModel.create({
          login_name: user_number,
          os,
          platform,
          browser,
          login_location,
          ipaddr: ip,
          status: "0",
          msg: "密码错误",
        });
        return (ctx.body = fail([], `密码错误!`, CODE.BUSINESS_ERROR));
      }
      if (user.status === "0") {
        return (ctx.body = fail(
          [],
          `用户已停用，请联系管理员!`,
          CODE.BUSINESS_ERROR
        ));
      }
      if (user.del_flag === "2") {
        await DataSystemLogininforModel.create({
          login_name: user_number,
          os,
          platform,
          browser,
          login_location,
          ipaddr: ip,
          status: "0",
          msg: "用户不存在，请联系管理员!",
        });
        return (ctx.body = fail(
          [],
          `用户不存在，请联系管理员!`,
          CODE.BUSINESS_ERROR
        ));
      }
      let datas = {
        user_id: user.user_id,
      };
      const token = jwt.sign(
        datas,
        secretOrkey,
        // 设置过期时间
        { expiresIn: expireTime }
      );
      let user_info = Object.assign({}, user.dataValues, { token });
      const post_info = await DataSystemUserPostModel.findPostInfoByUserID(
        user_info.user_id
      );
      const role_info = await DataSystemUserRoleModel.findRoleInfoByUserID(
        user_info.user_id
      );
      const role_ids = role_info.map((item) => {
        return item.role_id;
      });
      const dept_info = await DataSystemDeptModel.findDeptByUserID({
        user_id: user_info.user_id,
      });
      let permissions = [];
      let permission_perms = [];
      if (user_info.user_type === "00") {
        permissions = await DataSystemMenuModel.findAllPermission();
      } else {
        if (role_ids.length) {
          permissions = await DataSystemRoleMenuModel.findPermissionByRoleId({role_ids:role_ids.join(',')});
        }
      }
      permission_perms = permissions.map((item) => {
        return item.permission;
      });
      let user_data = Object.assign(
        {},
        { user_info: user_info },
        { post_info: post_info },
        { role_info: role_info },
        { dept_info: dept_info },
        { permissions: permission_perms }
      );
      setUserDataToRedis(user_info.user_id, user_data);
      await DataSystemUserModel.updateLoginInfo(ip, user_info.user_id);
      await DataSystemLogininforModel.create({
        login_name: user_number,
        os,
        platform,
        browser,
        login_location,
        ipaddr: ip,
        status: "1",
        msg: "登录成功!",
      });
      return (ctx.body = success({ token: token }, "登录成功", CODE.SUCCESS));
    } catch (error) {
      await DataSystemLogininforModel.create({
        login_name: user_number,
        os,
        platform,
        browser,
        login_location,
        ipaddr: ip,
        status: "0",
        msg: error.message,
      });
      return (ctx.body = fail([], error.message, CODE.BUSINESS_ERROR));
    }
  }
  /**
   * @description 退出登陆
   * @param {*} username
   * @param {*} password
   * @param {*} captcha
   */
  static async logout (ctx, next) {
    try {
      const token = ctx.request.headers.authorization;
      if (token) {
        // const { err, data } =
        jwt.verify(token.split('Bearer ')[1], secretOrkey, (err, data) => {
          if (!err) {
            deleteUserDataToRedis(data.user_id);
          }
          ctx.request.headers["authorization"] = "";
          ctx.cookies.set('token', null);
        })
      }
      return (ctx.body = success([], "退出成功", CODE.SUCCESS));
    } catch (error) {
      return (ctx.body = success([], "退出成功", CODE.SUCCESS));
    }
  }
  /**
   * @description 修改密码
   * @param {*} password
   * @param {*} newPassword
   */
  static async modifypwd (ctx, next) {
    const { password, newPassword } = ctx.request.body;
    try {
      const { user_id } = ctx.state.user;
      if (!password) {
        return (ctx.body = fail([], `请输入密码`, CODE.BUSINESS_ERROR));
      }
      const userInfo = await models.sys_user.findOne({
        where: {
          user_id,
          del_flag: "0",
        },
      });
      if (!userInfo) {
        return (ctx.body = fail([], `用户不存在`, CODE.BUSINESS_ERROR));
      }
      const vf = await validate(password, userInfo.password);
      if (vf) {
        const npassword = await encrypt(newPassword, saltTime);
        await models.sys_user.update(
          {
            password: npassword,
          },
          {
            where: {
              user_id,
            },
          }
        );
        return (ctx.body = success([], `更新成功`, CODE.SUCCESS));
      } else {
        return (ctx.body = fail([], "原密码错误", CODE.BUSINESS_ERROR));
      }
    } catch (error) {
      return (ctx.body = fail([], error.message, CODE.BUSINESS_ERROR));
    }
  }
  /**
   * @description 获取用户信息
   */
  static async userInfo (ctx, next) {
    const { user_id } = ctx.state.user;
    try {
      const userData = await getUserDataFromRedis(user_id);
      if (!userData) {
        return (ctx.body = fail([], `用户不存在`, CODE.BUSINESS_ERROR));
      }
      //
      let { permissions = [], user_info = {}, role_info = [] } = userData;
      if (user_info.user_type === "00") {
        permissions = ["*:*:*"];
      }
      let roles = role_info.map((item) => item.role_key);
      return (ctx.body = success(
        { permissions, user: user_info, roles },
        `success`,
        CODE.SUCCESS
      ));
    } catch (error) {
      return (ctx.body = fail([], error.message, CODE.BUSINESS_ERROR));
    }
  }

  /**
   * @description 添加用户
   * @param {*} username
   * @param {*} realname
   * @param {*} phone
   */
  static async userAdd (ctx, next) {
    const {
      dept_id,
      user_name,
      user_number,
      nick_name,
      user_type,
      email,
      phonenumber,
      sex,
      avatar,
      remark,
      postIds,
      roleIds,
    } = ctx.request.body;
    try {
      const { user_id: op_user_id } = ctx.state.user;
      if (!user_name || !user_number || !phonenumber) {
        ctx.body = fail([], `请输入用户名或手机号`);
        return;
      }
      const userInfo = await DataSystemUserModel.findUser({
        user_number,
        phonenumber,
      });
      if (userInfo.length) {
        ctx.body = fail([], `用户已存在`, CODE.BUSINESS_ERROR);
        return;
      }
      const npassword = await encrypt(config.defaultpassword, saltTime);
      await DataSystemUserModel.add({
        dept_id,
        user_name,
        password: npassword,
        user_number,
        nick_name,
        user_type,
        email,
        phonenumber,
        sex,
        avatar,
        remark,
        create_by: op_user_id,
        postIds,
        roleIds,
      });
      ctx.body = success([], `新增用户成功`, CODE.SUCCESS);
    } catch (error) {
      ctx.body = fail([], error.message, CODE.BUSINESS_ERROR);
    }
  }
  /**
   * @description 更新用户
   * @param {*} user_id
   * @param {*} username
   * @param {*} realname
   * @param {*} phone
   * @param {*} remark
   */
  static async userUpd (ctx, next) {
    const {
      user_id,
      dept_id,
      user_name,
      user_number,
      nick_name,
      user_type,
      email,
      phonenumber,
      sex,
      avatar,
      remark,
      postIds,
      roleIds,
    } = ctx.request.body;
    try {
      const { user_id: op_user_id } = ctx.state.user;
      if (!user_id) {
        ctx.body = fail([], `请输入必填项`);
        return;
      }
      const userInfo = await DataSystemUserModel.findOneNeUserId({
        user_name,
        user_number,
        phonenumber,
        user_id,
      });
      if (userInfo.length) {
        ctx.body = fail([], `用户名称或编码已存在`, CODE.BUSINESS_ERROR);
        return;
      }
      await DataSystemUserModel.updateUser({
        dept_id,
        user_name,
        user_number,
        nick_name,
        user_type,
        email,
        phonenumber,
        sex,
        avatar,
        remark,
        update_by: op_user_id,
        update_date: Date.now(),
        user_id,
        postIds,
        roleIds,
      });
      ctx.body = success([], `用户更新成功`, CODE.SUCCESS);
    } catch (error) {
      ctx.body = fail([], error.message, CODE.BUSINESS_ERROR);
    }
  }
  /**
   * @description 删除用户
   * @param {*} user_id
   */
  static async userDel (ctx, next) {
    const { user_id } = ctx.request.body;
    try {
      const { user_id: op_user_id } = ctx.state.user;
      if (!user_id) {
        ctx.body = fail([], `user_id 获取失败`);
        return;
      }
      await DataSystemUserModel.delete({ user_id, op_user_id });
      ctx.body = success([], `删除用户成功`, CODE.SUCCESS);
    } catch (error) {
      ctx.body = fail([], error.message, CODE.BUSINESS_ERROR);
    }
  }

  /**
   * @description 查找用户
   * @param {*} name
   */
  static async findUserByName (ctx, next) {
    const { realname } = ctx.request.body;
    try {
      const { user_id } = ctx.state.user;
      let sql = `SELECT user_id ,realname ,sex,avatar FROM sys_user WHERE (realname like "%${realname}%" or username like "%${realname}%") and delete_timestamp is null and user_id != ${user_id}`;
      const result = await models.sequelize.query(sql, {
        replacements: ["active"],
        type: models.sequelize.QueryTypes.SELECT,
      });
      ctx.body = success(result, "success");
    } catch (error) {
      ctx.body = fail([], error.message);
      return;
    }
  }
  /**
   * @description 批量添加角色
   * @param {String} name
   * @param {String} status
   */
  static async batchAddUser (ctx, next) {
    try {
      const { user_id, roleIds = [] } = ctx.request.body;
      if (!user_id || !roleIds.length) {
        return (ctx.body = fail([], `请输入必填项`));
      }
      const data = roleIds.map((role_id) => {
        return {
          user_id,
          role_id,
        };
      });
      await DataSystemUserRoleModel.bulkCreate({ data });
      return (ctx.body = success({}, `批量授权成功`));
    } catch (error) {
      return (ctx.body = fail([], error.message));
    }
  }
  /**
   * @description 取消用户授权
   * @param {String} name
   * @param {String} status
   */
  static async batchCancelRole (ctx, next) {
    try {
      const { user_id, role_ids = [] } = ctx.request.body;
      if (!user_id || !role_ids.length) {
        return (ctx.body = fail([], `请输入必填项`));
      }
      await DataSystemUserRoleModel.batchDestoryByUserId({ user_id, role_ids });
      return (ctx.body = success({}, `批量撤销授权成功`));
    } catch (error) {
      return (ctx.body = fail([], error.message));
    }
  }
  /**
   * @description 权限所有列表
   * @param {String} name
   * @param {String} status
   */
  static async list (ctx, next) {
    try {
      const {
        page_num,
        page_size,
        user_name,
        phonenumber,
        status,
        dept_id,
        user_number,
      } = ctx.request.query;
      const { data_scope = "" } = ctx.state;
      let limit = Number(page_num) || 1;
      let size = Number(page_size) || 10;
      const { result, count } = await DataSystemUserModel.list({
        limit,
        size,
        user_name,
        user_number,
        phonenumber,
        status: status,
        dept_id: Number(dept_id),
        data_scope,
      });
      return (ctx.body = success(
        { result, total: count[0].count },
        `获取岗位数据成功`,
        CODE.SUCCESS
      ));
    } catch (error) {
      return (ctx.body = fail([], error.message, CODE.BUSINESS_ERROR));
    }
  }
}

module.exports = {
  SysUserController,
};
